package com.fbee.smartcommunities.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fbee.smartcommunities.entity.Permission;
import com.fbee.smartcommunities.entity.User;
import com.fbee.smartcommunities.mapper.UserMapper;
import com.fbee.smartcommunities.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fbee.smartcommunities.utils.CustomizeException;
import com.fbee.smartcommunities.utils.IPUtil;
import com.fbee.smartcommunities.utils.JwtUtil;
import com.fbee.smartcommunities.utils.VerificationCodeGeneratorUtil;
import com.fbee.smartcommunities.vo.LoginVO;
import io.minio.errors.*;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author 汪佳泉
 * @since 2024-08-16
 */
@Service
@ConfigurationProperties(prefix = "login.role")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    // 存放普通用户的角色ID
    @Setter
    private Integer userRoleId;

    // 存放商家角色的角色ID
    @Setter
    private Integer businessRoleId;

    @Resource
    private UploadFileService uploadFileService;

    @Resource(name = "myRedis")
    private RedisTemplate redisTemplate;

    @Resource
    private EmailService emailService;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private UserMapper userMapper;

    @Resource
    private PermissionService permissionService;

    @Resource
    private LogService logService;

    @Resource
    private ConsumptionLogsService consumptionLogsService;

    @Resource
    private ShopService shopService;

    @Override
    public Boolean add(String name,
                       String nickname,
                       LocalDate birthday,
                       String phone,
                       String email,
                       String address,
                       String password,
                       Integer state,
                       Integer roleId,
                       MultipartFile file) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        if(file.getSize() == 0) {
            return this.save(new User(passwordEncoder.encode(password),
                    nickname, name, email, phone,
                    roleId, address, birthday, state));
        }
        return this.save(new User(passwordEncoder.encode(password),
                nickname, name, email, phone,uploadFileService.upload("images",file),
                roleId, address, birthday, state));
    }

    @Override
    public Boolean fixState(Long id, Boolean state) {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id",id);
        if(state == false){
            updateWrapper.set("state",1);
        } else {
            updateWrapper.set("state",0);
        }
        if(userMapper.update(null,updateWrapper)>0){
            // 更新成功
            return true;
        } else {
            // 更新失败
            return false;
        }
    }

    @Override
    public Page<User> getTargetList(Integer pageNo, Integer pageSize, String keyword, Integer roleId) {
        // 创建分页对象
        Page<User> page = new Page<>(pageNo,pageSize);
        // 创建条件构造器
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // 添加查询条件
        if(keyword != null){
            queryWrapper.like("name",keyword);
        }
        if(roleId != null){
            queryWrapper.eq("role_id",roleId);
        }
        return userMapper.selectPage(page,queryWrapper);
    }

    @Override
    public Boolean check(String column, String value,Integer id) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        long count;
        if(id != null){
            count = count(queryWrapper.eq(column, value).ne("id",id));
        } else {
            count = count(queryWrapper.eq(column, value));
        }
        if(count == 0){
            return true;
        }
        return false;
    }

    @Override
    public Boolean update(Integer id,
                          String name,
                          String nickName,
                          LocalDate birthday,
                          String phone,
                          String email,
                          String address,
                          MultipartFile file,
                          String icon) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id",id);
        if(name != null){
            updateWrapper.set("name",name);
        }
        if(nickName != null){
            updateWrapper.set("nick_name",nickName);
        }
        if(birthday != null) updateWrapper.set("birthday",birthday);
        if(phone != null) updateWrapper.set("phone",phone);
        if(email != null) updateWrapper.set("email",email);
        if(address != null) updateWrapper.set("address",address);
        if(file != null){
            updateWrapper.set("icon", uploadFileService.upload("images",file));
        } else {
            updateWrapper.set("icon",icon);
        }
        return userMapper.update(null,updateWrapper) > 0;
    }

    @Override
    public LoginVO login(String username, String password,String type,HttpServletRequest request) {
        User user = this.userVerification(username, password);
        if("商家登入".equals(type)){
            if(user.getRoleId() != businessRoleId){
                throw new CustomizeException("对不起,您的账号不具备该登入权限");
            }
        } else if("用户登入".equals(type)){
            if(user.getRoleId() != userRoleId){
                throw new CustomizeException("对不起,您的账号非普通账户请前往注册");
            }
        }
        System.out.println(user);
        return new LoginVO(JwtUtil.create(user),user.getId().longValue(),getPermissionByAdminId(new Long(user.getId()),request));
    }

    /**
     * 向邮箱发送验证码
     * @return
     */
    @Override
    public Boolean getCaptcha(String to,String state) throws MessagingException {
        // 生成一个验证码并将其存到缓存之中
        String code = VerificationCodeGeneratorUtil.generateFourDigitCode();
        redisTemplate.opsForValue().set(to,code,10, TimeUnit.MINUTES);
        String topic = null;
        String text = null;
        if("修改密码".equals(state)){
            topic =  "修改密码验证";
            text = "<h1>您正在尝试修改密码，请确保本人操作。<br>您的验证码为：</h1><h2>"+ code+"</h2>";
        } else if("普通注册".equals(state)){
            topic =  "未来蜂智慧社区注册验证";
            text = "<h1>您正在尝试注册未来蜂智慧社区账号，请确保本人操作。<br>您的验证码为：</h1><h2>"+ code+"</h2>";
        } else if("商家注册".equals(state)){
            topic =  "未来蜂商家入驻验证";
            text = "<h1>您正在尝试申请入驻未来蜂智慧社区商家社区，请确保本人操作。<br>您的验证码为：</h1><h2>"+ code+"</h2>";
        } else if("修改密码".equals(state)){
            topic =  "未来蜂修改密码验证";
            text = "<h1>您正在尝试修改密码，请确保本人操作。<br>您的验证码为：</h1><h2>"+ code+"</h2>";
        }
        emailService.sendCaptcha(to,topic,text);
        return true;
    }

    /**
     * 修改登入密码
     * @param username
     * @param password
     * @return
     */
    @Override
    @Transactional
    public Boolean fixPassword(String username, String password,String code) {
        boolean ok = redisTemplate.opsForValue().get(username).toString().equals(code);
        if(!ok) {
            throw new CustomizeException("验证码错误");
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email",username);
        User user = this.getOne(queryWrapper);
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("password",passwordEncoder.encode(password)).eq("email",username);
        if(this.update(updateWrapper)){
            // 清除掉验证码，防止下次使用
            return redisTemplate.delete(username);
        } else return false;
    }

    @Override
    public List<User> getUsersByNoticeTitle(String title) {
        List<User> users = userMapper.getUsersByNoticeTitle(title);
        if(users.size() > 0){
            return users;
        } else {
            ArrayList<User> users1 = new ArrayList<>();
            users1.add(new User("全部用户"));
            return users1;
        }
    }

    // 获取缓存中的验证码
    @Override
    public String getCode(String to) {
        if (redisTemplate.hasKey(to)) {
            return (String)redisTemplate.opsForValue().get(to);
        }
        return "null";
    }

    // 用户注册的方法
    @Override
    public Boolean registration(String email, String password, String code, Integer role) {
        boolean ok = redisTemplate.opsForValue().get(email).toString().equals(code);
        if(!ok) {
            throw new CustomizeException("验证码错误");
        }
        return this.save(new User(email,passwordEncoder.encode(password),role,0,"未来蜂用户" + VerificationCodeGeneratorUtil.generateFourDigitCode()));
    }

    /**
     * 转账
     * @param from
     * @param to
     * @param count
     * @return
     */
    @Override
    @Transactional
    public Boolean transfer(Long from, Long to, Double count,HttpServletRequest request,String content) {
        User fromAccount = getOne(new QueryWrapper<User>().eq("id", from));
        User toAccount = getOne(new QueryWrapper<User>().eq("id", to));
        if(fromAccount.getAccount().doubleValue() < count){
            throw new CustomizeException("您的账户余额不足");
        }
        if (!update(new UpdateWrapper<User>().eq("id", to).set("account",toAccount.getAccount().doubleValue() + count))) {
            throw new CustomizeException("付款异常");
        }
        if (!update(new UpdateWrapper<User>().eq("id", from).set("account",fromAccount.getAccount().doubleValue() - count))) {
            throw new CustomizeException("付款异常");
        }
        // 记录一条消费日志
        if (!consumptionLogsService.keepLog(content + count,from, IPUtil.getIP(request))) {
            throw new CustomizeException("付款异常");
        }
        if(!consumptionLogsService.keepLog("收入 +" + count,to,IPUtil.getIP(request))){
            throw new CustomizeException("付款异常");
        }
        return true;
    }

    /**
     * 完善个人信息
     * @param openId
     * @param name
     * @param nickName
     * @param birthday
     * @param phone
     * @param address
     * @param file
     * @return
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    @Override
    public String completeInformation(Integer openId, String name, String nickName, LocalDate birthday, String phone, String address, MultipartFile file, String icon) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        this.update(openId,name,nickName,birthday,phone,null,address,file,icon);
        // 获取到当前完善信息用户的roleID
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("id", openId));
        if(userRoleId == user.getRoleId()){
            return "用户登入";
        } else {
            return "商家登入";
        }
    }

    @Override
    public Boolean checkNull(Long uid) {
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("id", uid));
        if(user.getPhone() == null){
            return false;
        }
        return true;
    }

    @Override
    @Transactional
    public Boolean recharge(Double count, Long openId,HttpServletRequest request) {
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("id", openId));
        // 记录一条日志
        consumptionLogsService.keepLog("账户充值：" + count + "元",openId,IPUtil.getIP(request));
        return update(new UpdateWrapper<User>().eq("id",openId).set("account",user.getAccount().doubleValue() + count));
    }

    /**
     * 用户登入校验
     * @param username
     * @param password
     * @return
     */
    private User userVerification(String username,String password){
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone",username).or().eq("email",username);
        User admin = this.getOne(queryWrapper);
        if(admin == null){
            throw new CustomizeException("手机号或邮箱不正确");
        }
        if(!passwordEncoder.matches(password, admin.getPassword())){
            throw new CustomizeException("密码不正确");
        }
        if(admin.getState() == 1){
            throw new CustomizeException("该账户已被禁用");
        }
        return admin;
    }

    /**
     * 根据id来将用户的权限列表都查出来的同时记录日志
     * @param userId
     * @return
     */
    private List<Permission> getPermissionByAdminId(Long userId,HttpServletRequest request){
        // 记录一条日志
        // 获取IP地址，考虑到代理的问题
        String ip = IPUtil.getIP(request);
        logService.keepLog("登入系统",userId,ip);
        // 查询权限
        List<Permission> menu = new ArrayList<>();
        Set<String> backUrls = new HashSet<>();
        List<Permission> resources = permissionService.getResourcesByAdminId(userId);
        // 将这个里面所有目录都取出来 type == 1
        for (Permission permission : resources) {
            if(permission.getType().intValue() == 1) {
                if(permission.getParentId().intValue() == 0){
                    menu.add(permission);
                } else {
                    // 进到这个里面的都是二级目录
                    for(Permission parent : resources){
                        if(parent.getId().intValue() == permission.getParentId().intValue()){
                            List<Permission> children = parent.getChildren();
                            if(children == null){
                                children = new ArrayList<>();
                                parent.setChildren(children);
                            }
                            children.add(permission);
                        }
                    }
                }
            }
            if(permission.getBackUrl().trim() != "" || permission.getLevel() == 1){
                String []backs = permission.getBackUrl().split("\\,");
                for(String url : backs){
                    backUrls.add(url.trim());
                }
            }
        }
        // 将权限列表传入到redis缓存之中
        redisTemplate.opsForValue().set("user::" + userId + "::permission",backUrls,240, TimeUnit.MINUTES);
        return menu;
    }

}
